import json
import asyncio
import time
from typing import Dict, Any, List, Optional
import threading
import yaml
import logging

from util.tasker import Tasker
from util.serials import AsyncSerialDevice
from util.commander import Commander

# 配置基础日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - Client - %(levelname)s - %(message)s')
logger = logging.getLogger("ClientCommand")


class ClientCommand:
    def __init__(self,
                 serials_config_path="./configs/parameters.yaml",
                 code_config_path="./configs/settings.yaml",
                 save_config_path="./configs/saving.yaml",
                 ):
        # 移除Socket相关属性（用户需求）
        self.tasker = None
        self.serial = None
        self.save_dir = None
        self.connected = False  # 标记本地设备初始化状态
        # 配置路径
        self.serial_config_path = serials_config_path
        self.save_config_path = save_config_path
        self.code_config_path = code_config_path
        self.commander = None

    def _load_serial_config(self) -> Dict:
        """加载Serial配置（保持原逻辑）"""
        try:
            with open(self.serial_config_path, "r", encoding="utf-8") as f:
                config = yaml.safe_load(f)
            logger.info(f"✅ 成功加载Serial配置: {self.serial_config_path}")
            return config
        except Exception as e:
            logger.error(f"❌ Serial配置加载失败: {str(e)}", exc_info=True)
            raise

    def _load_save_config(self) -> Dict:
        """加载存储路径配置（保持原逻辑）"""
        try:
            with open(self.save_config_path, "r", encoding="utf-8") as f:
                config = yaml.safe_load(f)
            save_array = config.get("save", [])
            if not isinstance(save_array, list) or len(save_array) == 0:
                raise ValueError(f"配置文件 {self.save_config_path} 中 'save' 必须是非空数组")
            self.save_dir = "/".join(save_array)
            logger.info(f"✅ 成功加载并拼接存储路径: {self.save_dir}（源配置：{save_array}）")
            return config
        except Exception as e:
            logger.error(f"❌ 存储路径配置加载失败: {str(e)}", exc_info=True)
            raise

    # ------------------------------
    # 修改：connect方法
    # ------------------------------
    def connect(self):
        """初始化所有本地设备"""
        self.connected = False
        try:
            # 1. 初始化Tasker
            self.tasker = Tasker()
            logger.info("✅ Tasker已启动")

            # 3. 初始化Serial（保持原逻辑，优化等待连接方式）
            serial_config = self._load_serial_config()
            self.serial = AsyncSerialDevice(serial_config)
            logger.info("✅ 开始连接Serial...")

            # 同步等待Serial连接（避免异步回调嵌套）
            connect_event = threading.Event()
            connect_result = [False]

            async def _serial_connect_wrapper():
                connect_result[0] = await self.serial.connect()
                connect_event.set()

            self.tasker.add_task(_serial_connect_wrapper())
            if not connect_event.wait(timeout=5):  # 延长超时时间，确保Serial稳定连接
                raise TimeoutError("Serial连接超时（5秒未响应）")
            if not connect_result[0]:
                raise ConnectionError("Serial连接失败（返回False）")
            logger.info("✅ Serial已连接")

            # 4. 初始化Commander（保持原逻辑）
            self.commander = Commander(self.code_config_path)
            self.commander.connect()
            logger.info("✅ Commander已初始化")

            # 5. 加载存储配置（保持原逻辑）
            self._load_save_config()

            self.connected = True
            logger.info("✅ ClientCommand所有组件初始化完成，本地设备已就绪")

        except Exception as e:
            logger.error(f"❌ ClientCommand初始化失败: {str(e)}", exc_info=True)
            self.disconnect()  # 初始化失败时清理资源

    # ------------------------------
    # 修改：disconnect方法（资源清理）
    # ------------------------------
    def disconnect(self):
        """清理所有资源（清理逻辑）"""
        logger.info("🔄 开始清理ClientCommand资源...")

        # 2. 清理Tasker（保持原逻辑）
        if self.tasker:
            self.tasker.stop()
            logger.info("✅ Tasker已停止")

        # 3. 清理Serial（新增：确保Serial端口关闭）
        if self.serial and hasattr(self.serial, 'close'):
            self.serial.close()
            logger.info("✅ Serial端口已关闭")

        self.connected = False
        logger.info("🔚 ClientCommand资源清理完成")


    # ------------------------------
    # 保持原逻辑：指令处理与设备状态查询
    # ------------------------------
    def _process_single_command(self, cmd: dict):
        try:
            control_type = cmd.get("control_type")
            data = cmd.get("data", {})
            if not control_type or not data:
                logger.warning(f"⚠️ 无效指令格式: {cmd}")
                return

            name = data.get("name")
            action = data.get("action")
            if not name or not action:
                logger.warning(f"⚠️ 指令缺少参数: {data}")
                return

            # 根据control_type获取指令（保持原逻辑）
            if control_type == "key":
                hex_str = self.commander.key_message_dict[(name, action)]
            elif control_type == "flash":
                hex_str = self.commander.flash_message_dict[(name, action)]
            elif control_type == "linux":
                hex_str = self.commander.linux_message_dict[(name, action)]
            elif control_type == "discrete":
                hex_str = self.commander.discrete_message_dict[(name, action)]
            elif control_type == "power":
                hex_str = self.commander.power_message_dict[(name, action)]
            else:
                raise Exception(f"不支持的ControlType: {control_type}")

            self.tasker.add_task(self.serial.send_hex(hex_str))
            logger.info(f"✅ 已添加指令任务: {control_type} - {name}:{action}")

        except KeyError as e:
            logger.error(f"❌ 指令字典未找到匹配项: {(name, action)}（{control_type}）", exc_info=True)
        except Exception as e:
            logger.error(f"❌ 指令处理失败: {str(e)}（指令: {cmd}）", exc_info=True)

    async def _receive_device_power_status(self, msg_dict, name_key, action_key, idx):
        try:
            hex_cmd = msg_dict[(name_key, action_key)]
        except KeyError:
            logger.error(f"❌ 指令字典未找到键: ({name_key}, {action_key})")
            return 0

        success, rep = await self.serial.send_hex(hex_cmd)
        if not success or not rep:
            logger.warning(f"⚠️ 发送指令失败: ({name_key}, {action_key})")
            return 0

        try:
            bytes_list = [int(rep[i:i + 2], 16) for i in range(0, len(rep), 2)]
        except ValueError as e:
            logger.error(f"❌ 响应解析失败（{name_key}）: {str(e)}")
            return 0

        if len(bytes_list) <= idx:
            logger.warning(f"⚠️ 状态字节索引越界（{name_key}）: 长度{len(bytes_list)} < 索引{idx}")
            return 0

        return bytes_list[idx]

    async def _send_message_async(self, msg_dict, name, action, status_idx=3, target_bit=0):
        final_simple_list = []
        try:
            if not (0 <= target_bit <= 7):
                logger.error(f"❌ 目标bit非法：{target_bit}（仅支持0-7）")
                final_simple_list.append({"name": name, "status": False, "error": "无效bit位"})
                return final_simple_list

            if name == "discrete":
                # 处理多设备状态（保持原逻辑）
                for (signal_name, signal_action), _ in msg_dict.items():
                    status_byte = await self._receive_device_power_status(
                        msg_dict=msg_dict,
                        name_key=signal_name,
                        action_key=signal_action,
                        idx=status_idx
                    )
                    final_simple_list.append({
                        "name": signal_name,
                        "status": bool((status_byte >> target_bit) & 1),
                        "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
                    })
                logger.info(f"✅ discrete设备状态查询完成，生成{len(final_simple_list)}条记录")
            else:
                # 处理单设备状态（保持原逻辑）
                status_byte = await self._receive_device_power_status(
                    msg_dict=msg_dict,
                    name_key=name,
                    action_key=action,
                    idx=status_idx
                )
                final_simple_list.append({
                    "name": name,
                    "status": bool((status_byte >> target_bit) & 1) if status_byte >= 0 else False,
                    "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
                })
                logger.info(f"✅ 单设备状态查询完成：{name}-{action}")

        except Exception as e:
            error_msg = str(e)[:50]
            final_simple_list.append({
                "name": name,
                "status": False,
                "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
                "error": error_msg
            })
            logger.error(f"❌ 设备状态查询失败: {error_msg}", exc_info=True)

        return final_simple_list

    def _send_message(self, msg_dict, name, action):
        self.tasker.add_task(self._send_message_async(msg_dict, name, action))
        logger.info(f"📥 已提交设备状态查询任务：{name}-{action}")


# 测试代码（验证处理逻辑）
if __name__ == "__main__":
    client = ClientCommand()  # 修正拼写错误 clent -> client
    client.connect()  # 调用connect()方法进行初始化
    if client.connected:  # 检查connected属性状态
        print(client.commander.flash_message_dict)
        print(client.commander.power_message_dict)
    client.disconnect()  # 程序结束时清理资源